using System;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using Evaluant.Uss.Weave.PersistenceModel;
using System.Xml.Serialization;
using System.Collections;

namespace PersistenceManagerWeaver
{
	class Program
	{
        [STAThread]
		static int Main(string[] args)
		{
			string xml = String.Empty;
			string dll = String.Empty;
			string pdb = String.Empty;
			string output = String.Empty;

			ArgParser ap = new ArgParser(args);

			if(ap.Exists("?"))
			{
				Help();
				return 0;
			}

			if(!ap.Exists("xml"))
			{
				Console.WriteLine("Incorrect parameters : no Euss Weaving Model File is defined");
				Help();
				return 1;
			}

			if(!ap.Exists("dll"))
			{
				Console.WriteLine("Incorrect parameters : no assembly file is defined");
				Help();
				return 1;
			}

			xml = ap["xml"].Value;
			dll = ap["dll"].Value;

			if(!File.Exists(xml))
			{
				Console.WriteLine("The XML document does not exist.");
				return 2;           
			}

			if(!File.Exists(dll))
			{
				Console.WriteLine("The Dll file does not exist.");
				return 2;           
			}

			if(ap.Exists("out"))
				output = ap["out"].Value;
			else
				output = String.Empty;

			if(ap.Exists("pdb"))
				pdb = ap["pdb"].Value;
			else
				pdb = String.Empty;

			string[] xmlParts = xml.Split(new char[]{'\\'});
			Console.WriteLine("The document {0} is being processed...", xmlParts[xmlParts.Length - 1]);

            try
            {

                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(xml);

                string fileStrResult;

                using(TextReader tr = new StreamReader(xml))
                    fileStrResult = Regex.Replace(tr.ReadToEnd(), @"\sxmlns[^""]*\""[^""]*\""", String.Empty, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);

                Model persistentClasses;
                using (StringReader xmlReader = new StringReader(fileStrResult))
                {
                    XmlSerializer deserialize = new XmlSerializer(typeof(Model));
                    persistentClasses = (Model)deserialize.Deserialize(xmlReader);
                }

                EUSSWeaver eussweaver = new EUSSWeaver(persistentClasses, dll, output);

                if (pdb != String.Empty)
                {
					XmlTextReader reader = null;
					try
					{
						reader = new XmlTextReader(pdb);
						XmlSerializer serializer = new XmlSerializer(typeof(Pdb.Model.PdbInfos));
						eussweaver.PdbModel = (Pdb.Model.PdbInfos)serializer.Deserialize(reader);
					}
					catch
					{
						throw;
					}
					finally
					{
						reader.Close();
					}
                }

                string[] dllParts = dll.Split(new char[] { '\\' });
                string[] outputParts = output.Split(new char[] { '\\' });

                int weavingResult = eussweaver.Weave();
                string result = String.Empty;

                if (pdb != String.Empty)
                {
                    foreach (Mono.Cecil.TypeDefinition type in Mono.Cecil.AssemblyFactory.GetAssembly(dll).MainModule.Types)
                    {
                        Hashtable newMethods = Pdb.Tools.SymUtil.GetMethodDefinitionFromType(type);

                        foreach (Mono.Cecil.MethodDefinition method in newMethods.Values)
                        {
                            int newToken = (int)method.MetadataToken.RID + (int)Mono.Cecil.Metadata.TokenType.Method;
                            Pdb.Model.Method m = eussweaver.PdbModel.Methods.GetMethodByFullName(method.ToString());
                            if (m != null)
                            {
                                if (newToken != m.Token)
                                    m.Token = newToken;
                            }
                        }
                    }

					XmlTextWriter writer = null;
					try
					{
						XmlSerializer serializer = new XmlSerializer(typeof(Pdb.Model.PdbInfos));
						serializer.Serialize(writer, eussweaver.PdbModel);
					}
					catch
					{
						throw;
					}
					finally
					{
						writer.Close();
					}
                }


                switch (weavingResult)
                {
                    case 0:
                        if (output != String.Empty)
                            result = String.Concat("Success : The document ", output, " has been weaved");
                        else
                            result = String.Concat("Success : The document ", dllParts[dllParts.Length - 1], " has been weaved");
                        break;
                    case 1:
                        if (output != String.Empty)
                            result = String.Concat("Success : The document ", output, " has been weaved");
                        else
                            result = String.Concat("Success : The document ", dllParts[dllParts.Length - 1], " has been weaved");
                        break;
                    case 2:
                        result = String.Concat("Warning: No class is declared in ", xmlParts[xmlParts.Length - 1]);
                        break;
                }

                if (ap.Exists("verbose"))
                {
                    Console.WriteLine(result);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Source + " error: " + " " + e.Message);
            }
			return 0;
		}

		static public void Help()
		{
			Console.WriteLine(@"

Help for PersistenceManagerWeaver.exe

Generates an document by processing an XSLT tranformation on an existing XML document.

PersistenceManagerWeaver.exe /xml:xml_filename /dll:dll_filename [/out:output_filename] [/verbose]

	xml_filename
		Specify the Euss Weaving Model File which describes persistent fields and properties for your domain model 

	dll_filename
		Specify the assembly file which contains your own domain model

	output_filename
		Specify the weaved assembly file. If not provided, the weaved assembly will override the dll_filename

	/verbose
		If specified a message will be displayed at the begining and the end of the process
");

		}
	}
	
}
